package com.moon.aspects;

import com.moon.annotations.DataSource;
import com.moon.mapper.OperateLogMapper;
import com.moon.pojo.OperateLog;
import com.moon.utils.CurrentUserContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Arrays;

@Aspect
@Component
public class LogOperateAspect {

    @Autowired
    private OperateLogMapper operateLogMapper;
    @Pointcut("@annotation(com.moon.annotations.LogOperate)")
    public void logOperateCut() { }

    @Around("logOperateCut()")
    //    @DataSource("db02")
    /**
     * Spring AOP 不会代理自身的方法调用，也就是说：
     * logOperate() 方法加的 @DataSource("db02")；
     * 但是这个方法被 AOP 切面框架直接调用，而不是作为 Spring 管理的 Bean 方法被代理执行；
     * 所以切面 DynamicDataSourceAspect 拦截不到 logOperate() 方法上的注解，导致数据源没有切换。
     * 需要将注解内移到mapper层或者service层
     *
     * 更好的实现：可以调整LogOperate的切面实现,
     *  → 你不再需要把 @DataSource 加到 Mapper；
     *  →日志写入使用你定义的数据源；
     *  →数据源切换逻辑内聚在切面里，对业务无侵入。
     */
    /**
     * @Around("logOperateCut()")
     *     public Object logOperate(ProceedingJoinPoint point) throws Throwable {
     *         MethodSignature signature = (MethodSignature) point.getSignature();
     *         Method method = signature.getMethod();
     *         LogOperate logOperateAnnotation = method.getAnnotation(LogOperate.class);
     *
     *         String originalDs = null;
     *         boolean switched = false;
     *
     *         // 如果指定了数据源，手动切换
     *         if (logOperateAnnotation != null && !logOperateAnnotation.dataSource().isEmpty()) {
     *             originalDs = DataSourceContextHolder.getDataSourceKey(); // 备份原数据源
     *             DataSourceContextHolder.setDataSourceKey(logOperateAnnotation.dataSource());
     *             switched = true;
     *         }
     *
     *         long startTime = System.currentTimeMillis();
     *         Object result = point.proceed();
     *         long endTime = System.currentTimeMillis();
     *
     *         // 构建日志对象并插入，，略
     *
     *
     *         // 还原数据源
     *         if (switched) {
     *             if (originalDs != null) {
     *                 DataSourceContextHolder.setDataSourceKey(originalDs);
     *             } else {
     *                 DataSourceContextHolder.clear();
     *             }
     *         }
     *
     *         return result;
     *     }
     */


    public Object logOperate(ProceedingJoinPoint point) throws Throwable {
        // 记录开始时间
        long startTime = System.currentTimeMillis();
        // 执行方法
        Object result = point.proceed();
        // 当前时间
        long endTime = System.currentTimeMillis();
        // 耗时
        long costTime = endTime - startTime;

        // 构建日志对象
        OperateLog operateLog = new OperateLog();
        operateLog.setOperateEmpId(getCurrentUserId()); // 需要实现 getCurrentUserId 方法
        operateLog.setOperateTime(LocalDateTime.now());
        operateLog.setClassName(point.getTarget().getClass().getName());
        operateLog.setMethodName(point.getSignature().getName());
        operateLog.setMethodParams(Arrays.toString(point.getArgs()));
        operateLog.setReturnValue(result.toString());
        operateLog.setCostTime(costTime);

        // 插入日志
        operateLogMapper.insert(operateLog);
        return result;
    }


    public Integer getCurrentUserId() {
        return CurrentUserContextHolder.get().getId();
    }
}
